/***********************************************************
 *  File_Name  : XJPrivateHeap.h
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : 管理进程私有堆.
 *
 *  OS : Linux, UNIX, Windows
 *  LastVersion  : 20150918
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2015-9-18
 *  Version     : 20150918
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 *Desc:
		 1. XJPrivateHeap:		自动创建和销毁进程私有堆
								每一个该类的对象都代表一个私有堆, 所以
								该类对象的特点是: 一般声明周期都比较长
								通常作为全局对象, 其他类的静态成员对象
								或者一些长生命周期类对象的成员对象
		 2. XJPrivateHeapBuffer: 在私有堆中自动分配和释放指定大小的内存
								一般用于在函数体内分配和释放局部作用域的堆内存
								从而避免对 XJPrivateHeap::Alloc() 和
								XJPrivateHeap::Free() 的调用

Examples:
			XJPrivateHeap g_hpPrivate;

			int _tmain(int argc, _TCHAR* argv[])
			{
				XJPrivateHeapStrBuffer buff(g_hpPrivate, 32);
				lstrcpy(buff, _T("失败乃成功之母"));
				size_t size = buff.Size();
				buff.ReAlloc(40);
				size = buff.Size();
				std::cout << (TCHAR*)buff << '\n';
				// OR
				// ASSERT(g_hpPrivate.IsValid());
				// TCHAR* pch	= (TCHAR*)g_hpPrivate.Alloc(32 * sizeof(TCHAR));
				// lstrcpy(pch, _T("失败乃成功之母"));
				// size_t size = g_hpPrivate.Size(pch);
				// g_hpPrivate.ReAlloc(pch, 40 * sizeof(TCHAR));
				// size = g_hpPrivate.Size(pch);
				// std::cout << pch << '\n';
				// g_hpPrivate.Free(pch);
				//
				return 0;
			}
 ***********************************************************/

#ifndef SRC_XJPRIVATEHEAP_H_
#define SRC_XJPRIVATEHEAP_H_
#include "XJEnv.h"

#ifdef __GNUC__
#include <assert.h>
#define ASSERT assert
#endif

#ifndef _WIN32
#include <stdlib.h>
typedef void * HANDLE;
#else
#include <Windows.h>
#endif

namespace XJUtilClass{


class XJPrivateHeap
{
public:

	/*
	enum EnCreateOptions
	{
		CO_DEFAULT				= 0,
		CO_NO_SERIALIZE			= HEAP_NO_SERIALIZE,
		CO_GENERATE_EXCEPTIONS	= HEAP_GENERATE_EXCEPTIONS,
		CO_NOSERIALIZE_GENERATEEXCEPTIONS
								= HEAP_NO_SERIALIZE	|
								  HEAP_GENERATE_EXCEPTIONS
	};

	enum EnAllocOptions
	{
		AO_DEFAULT				= 0,
		AO_ZERO_MEMORY			= HEAP_ZERO_MEMORY,
		AO_NO_SERIALIZE			= HEAP_NO_SERIALIZE,
		AO_GENERATE_EXCEPTIONS	= HEAP_GENERATE_EXCEPTIONS,
		AO_ZEROMEMORY_NOSERIALIZE
								= HEAP_ZERO_MEMORY	|
								  HEAP_NO_SERIALIZE,
		AO_ZEROMEMORY_GENERATEEXCEPTIONS
								= HEAP_ZERO_MEMORY	|
								  HEAP_GENERATE_EXCEPTIONS,
		AO_NOSERIALIZE_GENERATESEXCEPTIONS
								= HEAP_NO_SERIALIZE	|
								  HEAP_GENERATE_EXCEPTIONS,
		AO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
								= HEAP_ZERO_MEMORY	|
								  HEAP_NO_SERIALIZE	|
								  HEAP_GENERATE_EXCEPTIONS
	};

	enum EnReAllocOptions
	{
		RAO_DEFAULT					= 0,
		RAO_ZERO_MEMORY				= HEAP_ZERO_MEMORY,
		RAO_NO_SERIALIZE			= HEAP_NO_SERIALIZE,
		RAO_GENERATE_EXCEPTIONS		= HEAP_GENERATE_EXCEPTIONS,
		RAO_REALLOC_IN_PLACE_ONLY	= HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_ZEROMEMORY_NOSERIALIZE
									= HEAP_ZERO_MEMORY			|
									  HEAP_NO_SERIALIZE,
		RAO_ZEROMEMORY_GENERATEEXCEPTIONS
									= HEAP_ZERO_MEMORY			|
									  HEAP_GENERATE_EXCEPTIONS,
		RAO_ZEROMEMORY_REALLOCINPLACEONLY
									= HEAP_ZERO_MEMORY			|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_NOSERIALIZE_GENERATESEXCEPTIONS
									= HEAP_NO_SERIALIZE			|
									  HEAP_GENERATE_EXCEPTIONS,
		RAO_NOSERIALIZE_REALLOCINPLACEONLY
									= HEAP_NO_SERIALIZE			|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
									= HEAP_GENERATE_EXCEPTIONS	|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
									= HEAP_ZERO_MEMORY			|
									  HEAP_NO_SERIALIZE			|
									  HEAP_GENERATE_EXCEPTIONS,
		RAO_ZEROMEMORY_NOSERIALIZE_REALLOCINPLACEONLY
									= HEAP_ZERO_MEMORY			|
									  HEAP_NO_SERIALIZE			|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_ZEROMEMORY_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
									= HEAP_ZERO_MEMORY			|
									  HEAP_GENERATE_EXCEPTIONS	|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
									= HEAP_NO_SERIALIZE			|
									  HEAP_GENERATE_EXCEPTIONS	|
									  HEAP_REALLOC_IN_PLACE_ONLY,
		RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
									= HEAP_ZERO_MEMORY			|
									  HEAP_NO_SERIALIZE			|
									  HEAP_GENERATE_EXCEPTIONS	|
									  HEAP_REALLOC_IN_PLACE_ONLY
	};

	enum EnSizeOptions
	{
		SO_DEFAULT		= 0,
		SO_NO_SERIALIZE	= HEAP_NO_SERIALIZE
	};

	enum EnFreeOptions
	{
		FO_DEFAULT		= 0,
		FO_NO_SERIALIZE	= HEAP_NO_SERIALIZE
	};

	enum EnCompactOptions
	{
		CPO_DEFAULT		= 0,
		CPO_NO_SERIALIZE	= HEAP_NO_SERIALIZE
	};
	*/

public:

	void * Alloc(size_t dwSize, unsigned long dwFlags = 0)
	{
#ifndef _WIN32
		m_dwSize = dwSize;
		return malloc(dwSize);
#else
		return ::HeapAlloc(m_hHeap, dwFlags, dwSize);
#endif
	}

	void * ReAlloc(void * pvMemory, size_t dwSize, unsigned long dwFlags = 0)
	{
#ifndef _WIN32
		m_dwSize = dwSize;
		return realloc(pvMemory, dwSize);
#else
		return ::HeapReAlloc(m_hHeap, dwFlags, pvMemory, dwSize);
#endif
	}

	size_t Size(void * pvMemory, unsigned long dwFlags = 0)
	{
#ifndef _WIN32
		return m_dwSize;
#else
		return ::HeapSize(m_hHeap, dwFlags, pvMemory);
#endif
	}

	bool Free(void * pvMemory, unsigned long dwFlags = 0)
	{
#ifndef _WIN32
		free(pvMemory);
		return true;
#else
		return ::HeapFree(m_hHeap, dwFlags, pvMemory);
#endif
	}

	size_t Compact(unsigned long dwFlags = 0)
	{
#ifndef _WIN32
		return 0;
#else
		return ::HeapCompact(m_hHeap, dwFlags);
#endif
	}

	bool IsValid() {
#ifndef _WIN32
		return true;
#else
		return m_hHeap != NULL;
#endif
	}

	bool Reset()
	{
#ifndef _WIN32
		return true;
#else
		if(IsValid()) ::HeapDestroy(m_hHeap);
		m_hHeap = ::HeapCreate(m_dwOptions, m_dwInitSize, m_dwMaxSize);
#endif
		return IsValid();
	}

public:
	XJPrivateHeap(unsigned long dwOptions = 0, size_t dwInitSize = 0, size_t dwMaxSize = 0)
	: m_dwOptions(dwOptions), m_dwInitSize(dwInitSize), m_dwMaxSize(dwMaxSize)
	{
#ifndef _WIN32
		m_hHeap = NULL;
#else
		m_hHeap = ::HeapCreate(m_dwOptions, m_dwInitSize, m_dwMaxSize);
#endif
	}

	~XJPrivateHeap	()	{
#ifndef _WIN32
#else
		if(IsValid()) ::HeapDestroy(m_hHeap);
#endif
	}
#ifndef _WIN32
#else
	operator HANDLE	()	{return m_hHeap;}
#endif

private:
	XJPrivateHeap(const XJPrivateHeap&);
	XJPrivateHeap operator = (const XJPrivateHeap&);

private:
#ifndef _WIN32
	HANDLE	m_hHeap;
#else
	void *m_hHeap;
#endif
	unsigned long	m_dwOptions;
	size_t	m_dwInitSize;
	size_t	m_dwMaxSize;
	size_t  m_dwSize;
};

template<class T>
class XJPrivateHeapBuffer
{
public:
	XJPrivateHeapBuffer(XJPrivateHeap& hpPrivate,
						size_t dwSize		= 0,
						unsigned long dwAllocFlags	= 0,
						unsigned long dwFreeFlags	= 0)
	: m_hpPrivate(hpPrivate)
	, m_dwAllocFlags(dwAllocFlags)
	, m_dwFreeFlags(dwFreeFlags)
	, m_pvMemory(NULL)
	{
		ASSERT(m_hpPrivate.IsValid());
		Alloc(dwSize);
	}

	~XJPrivateHeapBuffer() {Free();}

public:

	T* Alloc(size_t dwSize)
	{
		if(IsValid())
			Free();

		return m_pvMemory = (T*)m_hpPrivate.Alloc(dwSize * sizeof(T), m_dwAllocFlags);
	}

	T* ReAlloc(size_t dwSize, unsigned long dwFlags = 0)
		{return m_pvMemory = (T*)m_hpPrivate.ReAlloc(m_pvMemory, dwSize * sizeof(T), dwFlags);}

	size_t Size(unsigned long dwFlags = 0)
		{return m_hpPrivate.Size(m_pvMemory, dwFlags);}

	bool Free()
	{
		bool isOK = true;

		if(IsValid())
		{
			isOK = m_hpPrivate.Free(m_pvMemory, m_dwFreeFlags);
			m_pvMemory = NULL;
		}

		return isOK;
	}

	bool IsValid()			{return m_pvMemory != NULL;}
	operator T* ()	const	{return m_pvMemory;}

private:
	XJPrivateHeapBuffer(const XJPrivateHeapBuffer&);
	XJPrivateHeapBuffer operator = (const XJPrivateHeapBuffer&);

private:
	XJPrivateHeap&	m_hpPrivate;
	T*				m_pvMemory;
	unsigned long			m_dwAllocFlags;
	unsigned long			m_dwFreeFlags;
};

typedef XJPrivateHeapBuffer<XJ_BYTE_T>	XJPrivateHeapByteBuffer;
typedef XJPrivateHeapBuffer<XJ_TCHAR_T>	XJPrivateHeapStrBuffer;


}// namespace XJUtilClass{

#endif /* SRC_XJPRIVATEHEAP_H_ */
